package com.lyl.module.api.service;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.lyl.module.api.client.FileApiClient;
import com.lyl.module.constant.ALIYUN_GLOBAL_VARIABLE;
import com.lyl.module.utils.AliFileUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Mr.Luo
 * @date 2022-07-21 14:11
 * @desc 文件ApiService
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FileApiService {
    private final FileApiClient fileApiClient;

    /**
     * 获取文件列表
     *
     * @return JSONObject
     */
    public JSONObject getFileList(String parent_file_id) {
        Map<String, Object> map = new HashMap<>();
        map.put("drive_id", ALIYUN_GLOBAL_VARIABLE.DRIVE_ID);
        map.put("parent_file_id", parent_file_id);
        map.put("limit", 100);
        map.put("order_by", "updated_at");
        map.put("order_direction", "DESC");
        return fileApiClient.getFileList(map);
    }

    /**
     * 上传文件
     * @param file 文件
     * @param parentFileId 父级文件id
     * @return JSONObject
     * @throws IOException io异常
     */
    public JSONObject uploadFile(File file, String parentFileId) throws IOException {
        //上传文件
        JSONObject uploadFile = fileApiClient.uploadFile(preUploadParam(file, parentFileId));
        //文件秒传了
        if (Boolean.TRUE.equals(uploadFile.getBool("rapid_upload"))) {
            return uploadFile;
        }
        //分片上传
        JSONArray partInfoList = uploadFile.getJSONArray("part_info_list");
        if (ObjectUtil.isNotEmpty(partInfoList)) {
            //文件流位置
            long position = 0;
            //文件大小
            long size = file.length();

            for (int i = 0; i < partInfoList.size(); i++) {
                byte[] fileBytes;
                if (size > ALIYUN_GLOBAL_VARIABLE.DEFAULT_SIZE.longValue()) {
                    fileBytes = AliFileUtil.readBytes(file,(int) position, ALIYUN_GLOBAL_VARIABLE.DEFAULT_SIZE);
                } else {
                    fileBytes = AliFileUtil.readBytes(file,(int) position, (int) size);
                }
                String uploadUrl = partInfoList.getJSONObject(i).getStr("upload_url");
                //分片上传文件
                int code = AliFileUtil.uploadFileBytes(uploadUrl, fileBytes);
                double progress = ((double) (i + 1) / partInfoList.size()) * 100;
                log.info("文件：{} 上传进度：{}% 状态码： {}", file.getName(), NumberUtil.roundStr(progress, 2), code);
                position += ALIYUN_GLOBAL_VARIABLE.DEFAULT_SIZE;
                size -= ALIYUN_GLOBAL_VARIABLE.DEFAULT_SIZE;
            }
        }
        //合并分片
        Map<String, Object> map = new HashMap<>();
        map.put("drive_id", ALIYUN_GLOBAL_VARIABLE.DRIVE_ID);
        map.put("file_id", uploadFile.getStr("file_id"));
        map.put("upload_id", uploadFile.getStr("upload_id"));
        return fileApiClient.completeFile(map);
    }

    /**
     * 上传文件
     * @param file 文件
     * @param parentFileId 父级文件id
     * @return JSONObject
     * @throws IOException io异常
     */
    public JSONObject uploadFile(MultipartFile file, String parentFileId) throws IOException {
        //上传文件
        JSONObject uploadFile = fileApiClient.uploadFile(preUploadParam(file, parentFileId));
        //文件秒传了
        if (Boolean.TRUE.equals(uploadFile.getBool("rapid_upload"))) {
            return uploadFile;
        }
        //分片上传
        JSONArray partInfoList = uploadFile.getJSONArray("part_info_list");
        if (ObjectUtil.isNotEmpty(partInfoList)) {
            //文件流位置
            long position = 0;
            //文件大小
            long size = file.getSize();

            for (int i = 0; i < partInfoList.size(); i++) {
                byte[] fileBytes;
                if (size > ALIYUN_GLOBAL_VARIABLE.DEFAULT_SIZE.longValue()) {
                    fileBytes = Arrays.copyOfRange(file.getBytes(), (int) position, ALIYUN_GLOBAL_VARIABLE.DEFAULT_SIZE);
                } else {
                    fileBytes = Arrays.copyOfRange(file.getBytes(), (int) position, (int) size);
                }
                String uploadUrl = partInfoList.getJSONObject(i).getStr("upload_url");
                //分片上传文件
                int code = AliFileUtil.uploadFileBytes(uploadUrl, fileBytes);
                double progress = ((double) (i + 1) / partInfoList.size()) * 100;
                log.info("文件：{} 上传进度：{}% 状态码： {}", file.getOriginalFilename(), NumberUtil.roundStr(progress, 2), code);
                position += ALIYUN_GLOBAL_VARIABLE.DEFAULT_SIZE;
                size -= ALIYUN_GLOBAL_VARIABLE.DEFAULT_SIZE;
            }
        }
        //合并分片
        Map<String, Object> map = new HashMap<>();
        map.put("drive_id", ALIYUN_GLOBAL_VARIABLE.DRIVE_ID);
        map.put("file_id", uploadFile.getStr("file_id"));
        map.put("upload_id", uploadFile.getStr("upload_id"));
        return fileApiClient.completeFile(map);
    }

    /**
     * 上传文件
     * @param fileText 文件内容
     * @param parentFileId 父级文件id
     * @param fileName 文件名称
     * @return JSONObject
     * @throws IOException io异常
     */
    public JSONObject uploadFile(String fileText, String parentFileId,String fileName) throws IOException {
        //上传文件
        JSONObject uploadFile = fileApiClient.uploadFile(preUploadParam(fileText, parentFileId,fileName));
        //文件秒传了
        if (Boolean.TRUE.equals(uploadFile.getBool("rapid_upload"))) {
            return uploadFile;
        }
        //分片上传
        JSONArray partInfoList = uploadFile.getJSONArray("part_info_list");
        if (ObjectUtil.isNotEmpty(partInfoList)) {
            //文件流位置
            long position = 0;
            //文件大小
            long size = fileText.length();

            for (int i = 0; i < partInfoList.size(); i++) {
                byte[] fileBytes;
                if (size > ALIYUN_GLOBAL_VARIABLE.DEFAULT_SIZE.longValue()) {
                    fileBytes = Arrays.copyOfRange(fileText.getBytes(StandardCharsets.UTF_8), (int) position, ALIYUN_GLOBAL_VARIABLE.DEFAULT_SIZE);
                } else {
                    fileBytes = Arrays.copyOfRange(fileText.getBytes(StandardCharsets.UTF_8), (int) position, (int) size);
                }
                String uploadUrl = partInfoList.getJSONObject(i).getStr("upload_url");
                //分片上传文件
                int code = AliFileUtil.uploadFileBytes(uploadUrl, fileBytes);
                double progress = ((double) (i + 1) / partInfoList.size()) * 100;
                log.info("文件：{} 上传进度：{}% 状态码： {}", fileName, NumberUtil.roundStr(progress, 2), code);
                position += ALIYUN_GLOBAL_VARIABLE.DEFAULT_SIZE;
                size -= ALIYUN_GLOBAL_VARIABLE.DEFAULT_SIZE;
            }
        }
        //合并分片
        Map<String, Object> map = new HashMap<>();
        map.put("drive_id", ALIYUN_GLOBAL_VARIABLE.DRIVE_ID);
        map.put("file_id", uploadFile.getStr("file_id"));
        map.put("upload_id", uploadFile.getStr("upload_id"));
        return fileApiClient.completeFile(map);
    }

    private Map<String, Object> preUploadParam(MultipartFile file, String parentFileId) throws IOException {
        Map<String, Object> map = new HashMap<>();
        map.put("drive_id", ALIYUN_GLOBAL_VARIABLE.DRIVE_ID);
        map.put("part_info_list", AliFileUtil.getPartNumber(file.getSize()));
        map.put("parent_file_id", parentFileId);
        map.put("name", file.getOriginalFilename());
        map.put("type", "file");
        //map.put("check_name_mode", "refuse");
        //覆盖
        //map.put("check_name_mode", "overwrite");
        //保留两者
        map.put("check_name_mode", "auto_rename");
        map.put("size", file.getSize());
        map.put("content_hash", DigestUtil.sha1Hex(file.getInputStream()).toUpperCase());
        map.put("content_hash_name", "sha1");
        map.put("proof_code", AliFileUtil.getProofCode(file));
        map.put("proof_version", "v1");
        return map;
    }

    private Map<String, Object> preUploadParam(String fileText, String parentFileId,String fileName) throws IOException {
        Map<String, Object> map = new HashMap<>();
        map.put("drive_id", ALIYUN_GLOBAL_VARIABLE.DRIVE_ID);
        map.put("part_info_list", AliFileUtil.getPartNumber(fileText.length()));
        map.put("parent_file_id", parentFileId);
        map.put("name", fileName);
        map.put("type", "file");
        //map.put("check_name_mode", "refuse");
        //覆盖
        //map.put("check_name_mode", "overwrite");
        //保留两者
        map.put("check_name_mode", "auto_rename");
        map.put("size", fileText.length());
        map.put("content_hash", DigestUtil.sha1Hex(fileText).toUpperCase());
        map.put("content_hash_name", "sha1");
        map.put("proof_code", AliFileUtil.getProofCode(fileText.getBytes(StandardCharsets.UTF_8)));
        map.put("proof_version", "v1");
        return map;
    }

    private Map<String, Object> preUploadParam(File file, String parentFileId) throws IOException {
        Map<String, Object> map = new HashMap<>();
        map.put("drive_id", ALIYUN_GLOBAL_VARIABLE.DRIVE_ID);
        map.put("part_info_list", AliFileUtil.getPartNumber(file.length()));
        map.put("parent_file_id", parentFileId);
        map.put("name", file.getName());
        map.put("type", "file");
        //map.put("check_name_mode", "refuse");
        //覆盖
        //map.put("check_name_mode", "overwrite");
        //保留两者
        map.put("check_name_mode", "auto_rename");
        map.put("size", file.length());
        map.put("content_hash", DigestUtil.sha1Hex(file).toUpperCase());
        map.put("content_hash_name", "sha1");
        map.put("proof_code", AliFileUtil.getProofCode(file));
        map.put("proof_version", "v1");
        return map;
    }
}
